OpenCV棋盘角点检测原理总结 您所在的位置:网站首页 opencv 交叉点检测 OpenCV棋盘角点检测原理总结

OpenCV棋盘角点检测原理总结

2023-10-13 13:07| 来源: 网络整理| 查看: 265

对应于Opencv源码文件:\sources\modules\calib3d\src\calibinit.cpp 在这里插入图片描述 图1 :原始图片 第一步,局部平均自适应阈值化方法对亮度不均匀情况适应性强,因此用该方法对图像二值化,均衡化后得到了理想的门限,效果如图2所示。

在这里插入图片描述 在这里插入图片描述 第二步,图像膨胀分离各个黑块四边形的衔接,由于膨胀的是白色像素点,因此能够缩小黑块四边形,断掉衔接,效果如图3所示。 在这里插入图片描述

第三步,检测四边形,计算每个轮廓的凸包,多边形检测,以及判断是否只有四个顶点,若是则为四边形,再用长宽比、周长和面积等约束去除一些干扰四边形,效果如图4所示。 在这里插入图片描述

第四步,将每个四边形作为一个单元,它分别有邻近的四边形,无邻近四边形的为干扰四边形,两个邻近四边形为边界处四边形,四个邻近四边形为内部四边形。每个四边形的序号可按邻近关系排序,然后按对角两个四边形相对的两个点,取其连线的中间点作为角点, 效果如图5 所示。 在这里插入图片描述

整个棋盘定位过程是一个循环过程,先对读入的棋盘图像直方图均衡化,接着自适应(取决于flag参数)二值化,再对二值化后的图像膨胀。为了定位的鲁棒性,自适应二值化和膨胀所采用核的大小不能是唯一的,故不断的循环用不同的参数用对棋盘图像处理,膨胀所采用核的大小逐渐变大。

在每次的循环过程都需要,经过以下步骤。

1、在二值化后图像外围画一白色的矩形框(方便轮廓提取),然后进行轮廓提取cvFindContours。经过膨胀后的二值图像,每个黑色的方格已经被分开,轮廓提取后可以得到每个方格的轮廓,当然还有很多干扰轮廓。对轮廓进行多边形拟合cvApproxPoly,排除不是矩形的轮廓,利用矩形的其他性质,再排除一些干扰轮廓。这些工作主要由icvGenerateQuads函数完成。

2、寻找每个方格的相邻方格,并记相邻方格的个数,连同相邻方格的信息存在相应CvCBQuad结构体中。二值图像在膨胀后原本相邻的方格,分开了,原来相连部分有一个公共点,现在分开变成了两个点。找到相邻的方格之后,计算出原来的公共点,用公共点替代膨胀后分开的点。这主要由icvFindQuadNeighborhors函数完成。

3、对所有“方格”(包括被误判的)分类,分类的原则是类内所有方格是相邻的。由icvFindConnectedQuads函数完成。

4、根据已知所求的角点个数,判别每个类中方格是否为所求的棋盘方格,并对棋盘方格排序,即该方格位于哪行那列。在这个过程中,可以添加每类方格总缺少的方格,也可以删除每类方格中多余的方格。icvOrderFoundConnetedQuads函数完成该过程。

5、icvCleanFoundConnectedQuads函数、icvCheckQuadGroup函数根据已知棋盘的方格个数(由棋盘的角点数计算出来)确认方格位置及个数是否正确,并确定粗略强角点的位置(两个方格的相连位置)。icvCheckBoardMonotony再次检验棋盘方格是否提取正确。

6、以上如果有一步所有方格都不符合要求,则进入一个新的循环。若循环结束,还尚未找到符合要求的方格,则棋盘定位失败,退出函数。

最后,cvFindCornerSubpix()根据上步的强角点位置,确定强角点的精确位置。

bool cv::findChessboardCorners ( InputArray image, Size patternSize, OutputArray corners, int flags = CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE)

这个函数用来检测一幅图像中是否含有棋盘格,如果图像中不含有指定数目的棋盘格角点(即黑色方块相交的点为角点,因此制作标定板时,最好选用大一点白色或浅色木板作为棋盘格背景)或对它们排序失败时,函数返回0; 如果图像中棋盘格内部角点都被确定了位置并准确排列的话,该函数将它们按制定行列排序并存储在corners向量中。该函数确定的角点的大概位置(approximate),如果想更准确地确定角点的位置,你可以该函数检测角点成功后继续调用cornerSubPix函数。

参数:

image:8位灰度图像或彩色图像。

patternSizeNumber: 棋盘格内部角点的行和列,( patternSize = cvSize(points_per_row, points_per_colum) = cvSize(columns,rows) )。

cornersOutput:检测到的角点存储的数组,

flags:棋盘格检测角点方法设置标置位

CALIB_CB_ADAPTIVE_THRESH 使用自适应阈值将灰度图像转化为二值图像,而不是固定的由图像的平均亮度计算出来的阈值 CALIB_CB_NORMALIZE_IMAGE 在利用固定阈值或者自适应的阈值进行二值化之前,先使用equalizeHist来均衡化图像gamma值。 CALIB_CB_FILTER_QUADS 使用其他的准则(如轮廓面积,周长,类似方形的形状)来去除在轮廓检测阶段检测到的错误方块。 CALIB_CB_FAST_CHECK 在图像上快速检测一下棋盘格角点,如果没有棋盘格焦点被发现,绕过其它费时的函数调用,这可以在图像没有棋盘格被观测以及恶劣情况下缩短整个函数执行时间。 检测棋盘格角点并在图像中画出来的例子: Size patternsize(8,6); //interior number of corners

Mat gray = …; //source image

vector corners; //this will be filled by the detected corners

// CALIB_CB_FAST_CHECK saves a lot of time on images that do not contain any chessboard corners

bool patternfound = findChessboardCorners(gray, patternsize, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE + CALIB_CB_FAST_CHECK);

if(patternfound)

cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));

drawChessboardCorners(img, patternsize, Mat(corners), patternfound);

OpenCV findChessboardCorners 实现代码阅读, 主要实现在calibinit.cpp

bool cv::findChessboardCorners( InputArray _image, Size patternSize, OutputArray corners, int flags ){

CV_INSTRUMENT_REGION() int count = patternSize.area()*2; std::vector tmpcorners(count+1); Mat image = _image.getMat(); CvMat c_image = image; bool ok = cvFindChessboardCorners(&c_image, patternSize, (CvPoint2D32f*)&tmpcorners[0], &count, flags ) > 0; if( count > 0 ) { tmpcorners.resize(count); Mat(tmpcorners).copyTo(corners); } else corners.release(); return ok;

}

InputArray和OutputArray两个类都是代理数据类型,用来接收Mat和Vector作为输入参数,OutputArray继承自InputArray。

InputArray作为输入参数的时候,传入的参数加了const限定符,即它只接收参数作为纯输入参数,无法更改输入参数的内容。而OutputArray则没有加入限定符,可以对参数的内容进行更改。

InputArray这个接口类可以是Mat、Mat_、Mat_、vector、vector、vector。也就意味着如果看见函数的参数类型是InputArray型时,把上诉几种类型作为参数都是可以的。这个类只能作为函数的形参参数使用,不要试图声明一个InputArray类型的变量,可以用cv::Mat()或cv::noArray()作为空参。在函数的内部可以使用InputArray::getMat()函数将传入的参数转换为Mat的结构,方便函数内的操作。可能还需要InputArray::kind()用来区分Mat结构或者vector结构.

CV_IMPL int cvFindChessboardCorners( const void* arr, CvSize pattern_size,

CvPoint2D32f* out_corners, int* out_corner_count, int flags )

{

int found = 0; CvCBQuad *quads = 0; CvCBCorner *corners = 0; cv::Ptr storage; try{ int k = 0; const int min_dilations = 0; const int max_dilations = 7; if( out_corner_count ) *out_corner_count = 0; Mat img = cvarrToMat((CvMat*)arr).clone(); if( img.depth() != CV_8U || (img.channels() != 1 && img.channels() != 3) ) CV_Error( CV_StsUnsupportedFormat, "Only 8-bit grayscale or color images are supported" ); if( pattern_size.width


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有